#ifndef __SERIAL_H
#define __SERIAL_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "sys.h"
#include <stdint.h>

#if ENABLE_OS_SUPPORT
#include "FreeRTOS.h"
#include "semphr.h"
#endif

#define SERIAL_MINI_ENABLE 0
#define SERIAL_LOG_ENABLE 1
#define SERIAL_LOG_COLOR_ENABLE 0

#define SERIAL_PAYLOAD_SIZE 64
#define SERIAL_BUFFER_SIZE 256

    typedef struct Serial
    {
        uint8_t *payload;
        uint8_t *buffer;
        uint16_t size;
#if ENABLE_OS_SUPPORT
        SemaphoreHandle_t rx_complete;
        SemaphoreHandle_t tx_complete;
#else
    volatile uint8_t rx_complete;
    volatile uint8_t tx_complete;
#endif
        void *arg;
        void (*RecvCallback)(struct Serial *handle);
        void (*SendCallback)(struct Serial *handle, uint8_t *data, uint16_t size);
    } serial_t;

    typedef serial_t *serial_handle_t;

    typedef void (*serial_recv_cb_t)(serial_handle_t handle);
    typedef void (*serial_send_cb_t)(serial_handle_t handle, uint8_t *data, uint16_t size);

    serial_handle_t Serial_Init(void *arg, serial_recv_cb_t recv_cb, serial_send_cb_t send_cb);
    void Serial_DeInit(serial_handle_t handle);
    void Serial_Run(serial_handle_t handle);
    void Serial_Print(serial_handle_t handle, uint8_t *data, uint16_t size);

#if !SERIAL_MINI_ENABLE
    void Serial_Printf(serial_handle_t handle, const char *format, ...);
#endif

    void Serial_SendComplete(serial_handle_t handle);
    void Serial_RecvComplete(serial_handle_t handle, uint16_t size);

    typedef enum
    {
        kLogNone,
        kLogError,
        kLogWarn,
        kLogInfo,
    } log_level_t;

    typedef struct LogManager
    {
        log_level_t level;
        serial_handle_t serial;
    } log_manager_t;

    uint8_t Log_Init(serial_handle_t serial, log_level_t level);
    void Log_SetLevel(log_level_t level);
    log_manager_t *Log_GetLogManagerHandle(void);
    log_level_t Log_GetLevel(void);

#if SERIAL_LOG_ENABLE == 1
#if SERIAL_LOG_COLOR_ENABLE == 1

#if !SERIAL_MINI_ENABLE
#define LOGI(format, ...)                                                                                              \
    Serial_Printf(Log_GetLogManagerHandle()->serial, "\033[32m[Info] " format "\033[0m\n", ##__VA_ARGS__)
#define LOGW(format, ...)                                                                                              \
    Serial_Printf(Log_GetLogManagerHandle()->serial, "\033[33m[Warn] " format "\033[0m\n", ##__VA_ARGS__)
#define LOGE(format, ...)                                                                                              \
    Serial_Printf(Log_GetLogManagerHandle()->serial, "\033[31m[Error] " format "\033[0m\n", ##__VA_ARGS__)

#else

#define LOGI(format, ...)                                                                                              \
    if (Log_GetLevel() >= kLogInfo)                                                                                    \
    printf("\33[31m[Info] " format "\33[0m\n", ##__VA_ARGS__)
#define LOGW(format, ...)                                                                                              \
    if (Log_GetLevel() >= kLogWarn)                                                                                    \
    printf("\33[33m[Warn] " format "\33[0m\n", ##__VA_ARGS__)
#define LOGE(format, ...)                                                                                              \
    if (Log_GetLevel() >= kLogError)                                                                                   \
    printf("\33[31m[Error] " format "\33[0m\n", ##__VA_ARGS__)

#endif

#else

#if !SERIAL_MINI_ENABLE
#define LOGI(format, ...)                                                                                              \
    Serial_Printf(Log_GetLogManagerHandle()->serial, "[Info] " format "\n", ##__VA_ARGS__)
#define LOGW(format, ...)                                                                                              \
    Serial_Printf(Log_GetLogManagerHandle()->serial, "[Warn] " format "\n", ##__VA_ARGS__)
#define LOGE(format, ...)                                                                                              \
    Serial_Printf(Log_GetLogManagerHandle()->serial, "[Error] " format "\n", ##__VA_ARGS__)

#else

#define LOGI(format, ...)                                                                                              \
    if (Log_GetLevel() >= kLogInfo)                                                                                    \
    printf("[Info] " format "\n", ##__VA_ARGS__)
#define LOGW(format, ...)                                                                                              \
    if (Log_GetLevel() >= kLogWarn)                                                                                    \
    printf("[Warn] " format "\n", ##__VA_ARGS__)
#define LOGE(format, ...)                                                                                              \
    if (Log_GetLevel() >= kLogError)                                                                                   \
    printf("[Error] " format "\n", ##__VA_ARGS__)

#endif

#endif
#else

#define LOGI(format, ...)
#define LOGW(format, ...)
#define LOGE(format, ...)

#endif

#ifdef __cplusplus
}
#endif

#endif
